/*
 *    Copyright(c)2023-2024
 *    项目名称:hello-world
 *    文件名称:RepeatSubmitInterceptor.java
 *    Date:2023/11/18 下午11:45
 *    Author:赵士杰
 */

package com.hw.framework.interceptor;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.hw.common.annotation.RepeatSubmit;
import com.hw.common.constant.CacheConstants;
import com.hw.common.core.redis.RedisCache;
import com.hw.common.entity.AjaxResult;
import com.hw.common.utils.ip.IpUtils;
import com.hw.common.utils.servlet.ServletUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Project：hello-world
 * @ClassName：RepeatSubmitInterceptor
 * @Description：重复提交拦截器
 * @Author：Jie
 * @Date：2023/10/24 23:30
 */
@Component
public class RepeatSubmitInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisCache redisCache;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);

            if (annotation != null) {
                //获取请求参数

                String ipAddr = IpUtils.getIpAddr(request);
                String requestURI = request.getRequestURI();
                String requestMethod = request.getMethod();
                Map<String, String> requestParams = ServletUtils.getParamMap(request);
                Map<String, String> requestBody = getBodyString(request);

                Map<String,Object> cacheData = new HashMap<>();
                cacheData.put("ip",ipAddr);
                cacheData.put("uri",requestURI);
                cacheData.put("method",requestMethod);
                cacheData.put("params",requestParams);
                cacheData.put("body",requestBody);

                String jsonString = JSON.toJSONString(cacheData);

                String encrypt = encrypt(jsonString);
                Boolean b = redisCache.setCacheObjectIfAbsent(CacheConstants.REPEAT_SUBMIT_KEY+ipAddr+":"+encrypt, cacheData, annotation.interval(), TimeUnit.MILLISECONDS);

                if(b){
                   return true;
                }else {
                    AjaxResult ajaxResult = AjaxResult.error(annotation.message());
                    ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
                    return false;
                }
            }

            return true;
        }else {
            return true;
        }
    }

    public static String encrypt(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes());

            // Convert the byte array to hexadecimal string
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    public Map<String, String> getBodyString(HttpServletRequest request) throws IOException {
        // 获取请求体参数
        BufferedReader reader = request.getReader();
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }

        return JSONObject.parseObject(sb.toString(), HashMap.class);
    }

}
